package com.mingqijia.gassafety.job.job.warnStrategy;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gap.cache.redis.RedisCache;
import com.github.pagehelper.util.StringUtil;
import com.mingqijia.gassafety.db.entity.*;
import com.mingqijia.gassafety.db.mapper.*;
import com.mingqijia.gassafety.job.service.ConsumerService;
import com.mingqijia.gassafety.job.service.impl.CompanyServiceImpl;
import com.mingqijia.gassafety.job.service.impl.EquipmentServiceImpl;
import com.mingqijia.gassafety.job.service.impl.RunningStrategyServiceImpl;
import com.mingqijia.gassafety.shared.constant.Constants;
import com.mingqijia.gassafety.shared.constant.RedisTypeEnum;
import com.mingqijia.gassafety.shared.dto.AssembleTemplateDTO;
import com.mingqijia.gassafety.shared.utils.RedisCacheExt;
import com.mingqijia.gassafety.shared.utils.commonUtils.SnowflakeUtil;
import com.mingqijia.gassafety.shared.utils.message.SendMessageService;
import com.mingqijia.gassafety.shared.vcc.VccAuthoritiesProvider;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.mingqijia.gassafety.job.job.warnStrategy.WarnStrategyV2Job.getKeys;


/**
 * @author zhangfei
 * @version 1.0.0
 * @ClassName RunningStrategyJob.java
 * @Description TODO
 * @createTime 2023年12月15日
 */
@Component
@Slf4j
public class RunningStrategyJob {

    @Autowired
    RedisCacheExt redisUtil;

    @Autowired
    DtuMapper dtuMapper;
    @Autowired
    RunningStrategyReportMapper reportMapper;

    @Autowired
    RedisCache redisCache;
    @Autowired
    ConsumerMapper consumerMapper;
    @Autowired
    CustomerSubsMapper customerSubsMapper;
    @Autowired
    RunningStrategyExtMapper extMapper;
    @Autowired
    ContactsMapper contactsMapper;
    @Autowired
    SendMessageService sendMessageService;
    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RunningStrategyMapper warnStrategyMapper;
    @Autowired
    WarnStrategyMapper strategyMapper;
    @Autowired
    EquipmentServiceImpl equipmentService;
    @Autowired
    CompanyServiceImpl companyService;

    @Autowired
    BusinessNoticeMapper noticeMapper;

    @Autowired
    RunningRecordMapper runningRecordMapper;

    @Autowired
    InformRecordMapper informRecordMapper;

    @Autowired
    RunningStrategyServiceImpl runningStrategyService;

    @Autowired
    ReceiverValveMapper receiverValveMapper;
    public static final String split = ";";
    public static final String split_ = "-";
    private final Integer MaxRangeConstant = 3600000;
    //需要匹配的key
    private String patternKey = Constants.WARNING_EQUIPMENT_RUNNING + ":*";
    private String patternKey_BREAKDOWN = Constants.WARNING_EQUIPMENT_RUNNING_BREAKDOWN + ":*";

    public static final String CM_SERVICE_HOT_LINE = "cm_service_hot_line";

    @Autowired
    VccAuthoritiesProvider provider;

    @Autowired
    DeviceStateMapper deviceStateMapper;
    @Autowired
    DtuBindingOrderMapper dtuBindingOrderMapper;
    @Autowired
    ConsumerService consumerService;

    @Autowired
    RecordReceiverValveMapper recordReceiverValveMapper;


    /**
     *   0 0 8-22 1 * ? *
     */
    //@XxlJob("runningStrategyReport")
    public ReturnT<String> runningStrategyReport(String param) {
        XxlJobLogger.log("XXLJOB-runningStrategyReport start..." );
        log.info("runningStrategyReport--start--------");
        String key = Constants.EQUIPMENT_RUNNING_REPORT;
        try {
            Boolean acquire = redisUtil.setIfAbsent(key, String.valueOf(System.currentTimeMillis()), Constants.TIME_OUT);//15分钟超时
            if (acquire) {
                try {
                    //获取所有设备(多条设备对应多个规则)
                    List<Map<String, Object>> consumers = dtuMapper.reportAllConsumer(2, StringUtil.isEmpty(param)?
                            DateUtil.format(DateUtil.offsetMonth(new Date(),-1),"yyyy-MM"):param );
                    execute(consumers);
                    return ReturnT.SUCCESS;
                } catch (Exception e) {
                    log.info("runningStrategyReport-error:{}", e);
                } finally {
                    redisUtil.del(key);
                }
            }
        } catch (Exception e) {
            log.info("runningStrategyReport-error:{}", e);
        }
        log.info("runningStrategyReport--end--------");
        XxlJobLogger.log("XXLJOB-runningStrategyReport end..." );
        return ReturnT.SUCCESS;
    }

    private boolean execute(List<Map<String, Object>> consumers) {
        log.info("runningStrategyReport-execute：{}", JSONObject.toJSONString(consumers));
        if (!CollectionUtil.isEmpty(consumers)) {
            for (Map<String, Object> consumerMap : consumers) {
                Object custType = consumerMap.get("cust_type");
                    if (!"民用".equals(custType)){
                        log.info("runningStrategyReport-custType：{}", custType);
                        return false;
                    }
                String orgCode = consumerMap.get("org_code")+"";
                String consumerId = consumerMap.get("consumerId")+"";
                String adviceType = consumerMap.get("advice_type")+"";
                String consumerName = consumerMap.get("name")==null?Constants.BLANK:consumerMap.get("name").toString();
                Long strategyId = Long.parseLong(StringUtil.isNotEmpty(consumerMap.get("strategyId")+"")
                        ?consumerMap.get("strategyId")+"":"0L");
                log.info("execute-strategyId:{},adviceType:{},orgCode:{}",strategyId,adviceType,orgCode);
                if (strategyId==0L) continue;
                if (StringUtils.isEmpty(adviceType)) continue;
                List<String> adviceTypes = new ArrayList<>();
                if (adviceType.contains(split)) {
                    adviceTypes = new ArrayList<>(Arrays.asList(adviceType.split(split)));
                }
                QueryWrapper<RunningStrategyExt> extQueryWrapper = new QueryWrapper<>();
                extQueryWrapper.lambda().or().eq(RunningStrategyExt::getIsDeleted,0)
                        .eq(RunningStrategyExt::getStrategyId,strategyId);
                List<RunningStrategyExt> runningStrategyExts = extMapper.selectList(extQueryWrapper);
                log.info("execute-runningStrategyExts:{}",JSONObject.toJSONString(runningStrategyExts));
                if (!CollectionUtils.isEmpty(runningStrategyExts)){
                    QueryWrapper<BusinessNotice> query = new QueryWrapper<>();
                    query.lambda().or().eq(BusinessNotice::getIsDeleted, 0)
                            .eq(BusinessNotice::getSpId, runningStrategyExts.get(0).getSpId())
                            .eq(BusinessNotice::getParamCode, CM_SERVICE_HOT_LINE);
                    List<BusinessNotice> r = noticeMapper.selectList(query);
                    String phone = "";
                    if (!CollectionUtil.isEmpty(r)) phone = r.get(0).getParamValue();
                    List<Map<String, Object>> list = contactsMapper.selectInfo(consumerId);
                    long snowflakeId = SnowflakeUtil.getSnowflakeId();

                    AssembleTemplateDTO assembleTemplateDTO = new AssembleTemplateDTO();
                    assembleTemplateDTO.setReport(2);
                    assembleTemplateDTO.setPhone(phone);
                    assembleTemplateDTO.setImei("");
                    assembleTemplateDTO.setEquipmentType("");
                    assembleTemplateDTO.setInstallationPosition("");
                    assembleTemplateDTO.setConsumerName(consumerName);
                    assembleTemplateDTO.setSmsMsgCode(StringUtils.isEmpty(consumerMap.get("sms_msg_code"))?"":consumerMap.get("sms_msg_code").toString());
                    assembleTemplateDTO.setWxMsgCode(StringUtils.isEmpty(consumerMap.get("wx_msg_code"))?"":consumerMap.get("wx_msg_code").toString());

                    assembleTemplateDTO.setEquipmentName("");
                    assembleTemplateDTO.setCustAddress(null==consumerMap.get("cust_address")?"":consumerMap.get("cust_address").toString());
                    assembleTemplateDTO.setSubsCode(null==consumerMap.get("subs_code")?"":consumerMap.get("subs_code").toString());
                    assembleTemplateDTO.setSpId(runningStrategyExts.get(0).getSpId());

                    Map<String, Object> assembleTemplate = runningStrategyService.getAssembleTemplate(assembleTemplateDTO,1);
                    runningStrategyService.routeReport(consumerMap,snowflakeId,consumerId,list,strategyId,runningStrategyExts,new Date(),assembleTemplate,adviceTypes,runningStrategyExts.get(0).getSpId());
                }
            }
        }
        return false;
    }


    /**
     * 一小时一次 0 0 0/1 * * ?
     */
    @XxlJob("runningStrategyAgain")
//    @Scheduled(cron = "0 0/1 * * * ?")
    public ReturnT<String> runningStrategyAgain(String param) {
        log.info("runningStrategyAgain--start--------");
        XxlJobLogger.log("XXLJOB-runningStrategyAgain start..." );
        String redisKey = Constants.EQUIPMENT_RUNNING_AGAIN;
        try {
            Boolean acquire = redisUtil.setIfAbsent(redisKey, String.valueOf(System.currentTimeMillis()), Constants.TIME_OUT);//15分钟超时
            if (acquire) {
                try {
                    List<String> keys = getKeys(redisTemplate, patternKey);
                    keys.addAll(getKeys(redisTemplate, patternKey_BREAKDOWN));
                    if (!CollectionUtil.isEmpty(keys)) {
                        log.info("runningStrategyAgain-本次扫描到需要执行的数据：{}", JSONObject.toJSONString(keys));
                        for (String key : keys) {
                            Map<String, Object> cacheMap = redisCache.getCacheMap(key);
                            if (cacheMap == null||cacheMap.size()==0) continue;
                            Object iMEI = cacheMap.get("iMEI");
                            Object strategyId = cacheMap.get("strategyId");
                            Object type = cacheMap.get("type");
                            String iMEIString = iMEI.toString();
                            //判断当前设备是否有绑定
                            Dtu dtu = dtuMapper.selectByImei(iMEI+"", null);
                            if (dtu == null) {
                                redisCache.deleteObject(key);
                                //更新数据
                                updateRecordStatus(iMEI + "", cacheMap.get("identificationCode") + "", 1);
                                log.info("runningStrategyAgain-删除队列中的key,原因dtu不符合条件：{}", key);
                                continue;
                            }

                            String[] split = key.split(RedisTypeEnum.getPushTypes(StringUtil.isEmpty(type+"")?0:Integer.parseInt(type+"")).getName() + ":");
                            if (split.length < 2) return ReturnT.SUCCESS;
                            DeviceState deviceState = deviceStateMapper.selectByDeviceId(iMEIString, dtu.getSpId());
                            if (deviceState == null) continue;
                            Integer status = deviceState.getDeviceStatus();

                            String subId = "";
                            if (status != 0&&status != 4) {
                                log.info("runningStrategyAgain-设备状态已变更:{}", iMEI);
                                redisCache.deleteObject(key);
                                updateRecordStatus(iMEI + "", cacheMap.get("identificationCode") + "", 1);
                                continue;
                            }
                            List<Map<String, Object>> dtuMaps = dtuMapper.runningAllEquipment(null,iMEIString ,Integer.parseInt(type+"")==0?1:0);
                            log.info("runningStrategyAgain-dtuMaps:{}", JSONObject.toJSONString(dtuMaps));
                            if (CollectionUtils.isEmpty(dtuMaps)) continue;
                            Map<String, Object> dtuMap = dtuMaps.get(0);
                            String snowflakeId =cacheMap.get("identificationCode")+"";
                            RunningStrategy warnStrategy = warnStrategyMapper.selectById(strategyId + "");
                            if (warnStrategy == null || warnStrategy.getIsDeleted() || warnStrategy.getIsDisabled() == 1) {
                                redisCache.deleteObject(key);
                                log.info("runningStrategyAgain-删除队列中的key原因策略关闭：{}", key);
                                //更新数据
                               updateRecordStatus(iMEI + "",  snowflakeId+ "", 1);
                                continue;
                            }
                            String adviceType = StringUtils.isEmpty(dtuMap.get("advice_type")) ? "" : dtuMap.get("advice_type") + "";
                            Integer strategyType = StringUtils.isEmpty(dtuMap.get("strategy_type")) ? -1 :
                                    Integer.parseInt(dtuMap.get("strategy_type") + "");

                            log.info("runningStrategyAgain-adviceType:{},strategyType:{},deviceState:{}", adviceType,strategyType,JSONObject.toJSONString(deviceState));
                            int i = 0;
                            Integer report;
                            if (status == 0 && strategyType == 1) {
                                report = 0;
                                log.info("runningExecute-设备已经离线:{},{}",iMEIString, status);
                                detailOptAgain(cacheMap, iMEI + "", subId, report, snowflakeId,key, adviceType, strategyType,dtu,warnStrategy,dtuMap);
                            } else if (strategyType == 1) {
                                    if (Integer.parseInt(cacheMap.get("type") + "") != 0) continue;
                                    redisCache.deleteObject(Constants.WARNING_EQUIPMENT_RUNNING + ":" + (iMEI.toString().contains("-")|| StringUtil.isEmpty(subId) ? iMEI : iMEI + "-" + subId));
                                    //更新数据
                                    updateRecordStatus(iMEI + "", cacheMap.get("identificationCode") + "", 1);
                                    log.info("runningExecute-删除队列中的key,原因dtu不符合离线条件：{}", Constants.WARNING_EQUIPMENT_RUNNING + ":" + (iMEI.toString().contains("-")|| StringUtil.isEmpty(subId) ? iMEI : iMEI + "-" + subId));
                            }
                            if (status == 4 && strategyType == 0) {
                                report = 1;
                                log.info("runningExecute-设备状态为故障:{},{}", iMEIString, status);
                                detailOptAgain(cacheMap, iMEI + "", subId, report, snowflakeId,key, adviceType, strategyType,dtu,warnStrategy,dtuMap);
                            } else if (strategyType == 0) {
                                    if (Integer.parseInt(cacheMap.get("type") + "") != 1) continue;
                                    redisCache.deleteObject(Constants.WARNING_EQUIPMENT_RUNNING_BREAKDOWN + ":" + (iMEI.toString().contains("-")|| StringUtil.isEmpty(subId) ? iMEI : iMEI + "-" + subId));
                                    //更新数据
                                    updateRecordStatus(iMEI + "", cacheMap.get("identificationCode") + "", 1);
                                    log.info("runningExecute-删除队列中的key,原因dtu不符合故障条件：{}", Constants.WARNING_EQUIPMENT_RUNNING_BREAKDOWN + ":" + (iMEI.toString().contains("-") || StringUtil.isEmpty(subId)? iMEI : iMEI + "-" + subId));
                            }
                        }
                    }
                } catch (Exception e) {
                    log.info("runningStrategyAgain-error:{}", e);
                } finally {
                    redisUtil.del(redisKey);
                }
            }
        } catch (Exception e) {
            log.info("runningStrategyAgain-error:{}", e);
        }
        log.info("runningStrategyAgain--end--------");
        XxlJobLogger.log("XXLJOB-runningStrategyAgain end..." );
        return ReturnT.SUCCESS;
    }

    private void detailOptAgain(Map<String, Object> cacheMap, String iMEI , String subId,Integer report,  String snowflakeId,
           String key, String adviceType, Integer strategyType,Dtu dtu,RunningStrategy warnStrategy,Map<String, Object> dtuMap) {
        if (StringUtils.isEmpty(adviceType) || strategyType == -1) return;
        List<String> adviceTypes = new ArrayList<>();
        if (adviceType.contains(split)) {
            adviceTypes = new ArrayList<>(Arrays.asList(adviceType.split(split)));
        }
        log.info("runningExecute-adviceTypes:{}", adviceTypes);
        Object nextSendTime = cacheMap.get("nextSendTime");
        Object nextWxInterval = cacheMap.get("nextWxTime");
        Object nextCallInterval = cacheMap.get("nextCallTime");
        log.info("detailOptAgain---nextSendTime:{},nextWxInterval:{},nextCallInterval:{}", nextSendTime
                , nextWxInterval, nextCallInterval);
        if ( nextSendTime == null && nextWxInterval == null && nextCallInterval == null) return;
        String con = dtu.getConsumerId() + "";
        List<Map<String, Object>> list = contactsMapper.selectInfo(con);
        Long strategyId = warnStrategy.getId();
        boolean updateStatus = true;
        if (strategyId != null) {
            QueryWrapper<RunningStrategyExt> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(RunningStrategyExt::getIsDeleted, 0)
                    .eq(RunningStrategyExt::getStrategyId, strategyId)
                    .orderByAsc(RunningStrategyExt::getSort);
            List<RunningStrategyExt> exts = extMapper.selectList(queryWrapper);
            if (!CollectionUtil.isEmpty(exts)) {
                Date date = new Date();
                long time = date.getTime();
                int i=0;
                boolean nextSend = checkSendRun(snowflakeId, iMEI, key, nextSendTime, time, i);
                boolean nextWx = checkSendRun(snowflakeId, iMEI, key, nextWxInterval, time, i);
                boolean nextCall = checkSendRun(snowflakeId, iMEI, key, nextCallInterval, time, i);
                if (nextSend&& nextWx&& nextCall) return;
                Object sendCount = cacheMap.get("count");
                if (sendCount == null) return;
                Integer count = Integer.parseInt(sendCount + "");
                cacheMap.put("count", count + 1);   //总次数
                cacheMap.put("ruleCount", exts.size());//当前规则总数
                cacheMap.put("strategyId", strategyId);
                cacheMap.put("type", report);
                QueryWrapper<BusinessNotice> query = new QueryWrapper<>();
                query.lambda().or().eq(BusinessNotice::getIsDeleted, 0)
                        .eq(BusinessNotice::getSpId, warnStrategy.getSpId())
                        .eq(BusinessNotice::getParamCode, CM_SERVICE_HOT_LINE);
                List<BusinessNotice> r = noticeMapper.selectList(query);
                String phone = "";
                if (!CollectionUtil.isEmpty(r)) phone = r.get(0).getParamValue();
                String imei = cacheMap.get("iMEI") + "";
                if (!dtu.getEquipmentType() .equals("Gas_alarm_controller") && imei.contains("-")) {
                    String[] iMEIS = imei.split("-");
                    imei = iMEIS[0];
                }
                String equipmentType = null==dtuMap.get("equipment_type")?"":dtuMap.get("equipment_type").toString();
                String installationPosition = null==dtuMap.get("installation_position")?"":dtuMap.get("installation_position").toString();
                String custAddress = null==dtuMap.get("cust_address")?"":dtuMap.get("cust_address").toString();
                String consumerName = null==dtuMap.get("consumerName")?"":dtuMap.get("consumerName").toString();
                String equipmentName = null==dtuMap.get("equipmentName")?"":dtuMap.get("equipmentName").toString();
                AssembleTemplateDTO assembleTemplateDTO = new AssembleTemplateDTO();
                assembleTemplateDTO.setReport(report);
                assembleTemplateDTO.setPhone(phone);
                assembleTemplateDTO.setImei(imei);
                assembleTemplateDTO.setEquipmentType(equipmentType);
                assembleTemplateDTO.setInstallationPosition(installationPosition);
                assembleTemplateDTO.setConsumerName(consumerName);
                assembleTemplateDTO.setEquipmentName(equipmentName);
                assembleTemplateDTO.setCustAddress(custAddress);
                assembleTemplateDTO.setConsumerId(con);
                assembleTemplateDTO.setCustName(StringUtils.isEmpty(dtuMap.get("custName")) ? dtuMap.get("cust_name") + "" : dtuMap.get("custName") + "");
                assembleTemplateDTO.setSubsCode(null==dtuMap.get("subs_code")?"":dtuMap.get("subs_code").toString());
                assembleTemplateDTO.setSpId(warnStrategy.getSpId());
                Map<String, Object> assembleTemplate = runningStrategyService.getAssembleTemplate(assembleTemplateDTO,0);
                log.info("runningExecute-assembleTemplate:{}", JSONObject.toJSON(assembleTemplate));
                runningStrategyService.route(dtuMap, iMEI, subId, report, Long.parseLong(snowflakeId), con, list, strategyId, exts, cacheMap, date, assembleTemplate, adviceTypes, key,nextSend,nextWx,nextCall);
                log.info("runningExecute-cacheMap:{}", JSONObject.toJSON(cacheMap));
                redisCache.setCacheMap(key, cacheMap);
                redisTemplate.expire(key, 32, TimeUnit.DAYS);
            }
        } else {
            //策略被禁用了
            redisCache.deleteObject(key);
            //更新数据
            updateRecordStatus(iMEI,cacheMap.get("identificationCode") + "", 1);
            log.info("warnStrategyAgain-删除队列中的key原因是策略被禁用：{}", key);
        }

        if (updateStatus) redisCache.setCacheMap(Constants.WARNING_EQUIPMENT + ":" + iMEI, cacheMap);
    }
    public void updateRecordStatus(String imei, String taskIdentificationCode, int status) {
        InformRecord warningRecord = new InformRecord();
        warningRecord.setTaskIdentificationCode(taskIdentificationCode);
        warningRecord.setEndTime(new Date());
        warningRecord.setStatus(status);
        QueryWrapper<InformRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().or()
                .eq(InformRecord::getTaskIdentificationCode, taskIdentificationCode);
        informRecordMapper.update(warningRecord, queryWrapper);
    }

    private boolean checkSendRun(String snowflakeId, String iMEI, String key, Object nextSendTime, long time,int i
    ) {
        log.info("runningCheckSendRun-params:{},{},{}",iMEI,nextSendTime,time);
        if (nextSendTime != null) {
            log.info("runningStrategyAgain-距离执行时间差额：{}", time - Long.parseLong(nextSendTime + ""));
            //超过10分钟没有发送，清除
            if (time - Long.parseLong(nextSendTime + "") >= MaxRangeConstant) {
                i++;
                if (i==3){
                 redisCache.deleteObject(key);
                updateRecordStatus(iMEI,snowflakeId, 1);
                log.info("runningStrategyAgain-超时清除：{}", key);
                }
            }
        }
        if (!(nextSendTime != null && time - Long.parseLong(nextSendTime + "")
                <= MaxRangeConstant
                && time - Long.parseLong(nextSendTime + "") >= 0)) return true;
        return false;
    }

}